import {
	IAbility,
	IActionModel,
	IContext,
	IMDCtrlAbility,
	IParam,
	IRedirectInput,
	IRedirectResult,
	IUIActionResult,
	IUIService,
	IViewAbility,
	IViewDetail,
} from '@/core/interface';
import { deepCopy, formatActionData, hasFunction } from '../../utils/util';

/**
 * 界面服务基类
 *
 * @export
 * @class UIService
 */
export abstract class UIServiceBase implements IUIService {
	/**
	 * 是否启用主状态
	 *
	 * @protected
	 * @type {boolean}
	 * @memberof UIService
	 */
	public isEnableDEMainState = false;

	/**
	 * 流程状态数组
	 *
	 * @protected
	 * @type {Array<string>}
	 * @memberof UIServiceBase
	 */
	public InWorkflowArray: Array<string> = ['todo', 'toread'];

	/**
	 * 执行界面行为
	 * @param tag 界面行为标识
	 * @param context 应用上下文
	 * @param viewParams 视图参数
	 * @param data 业务数据
	 * @param event 事件对象
	 * @param ability 当前环境能力
	 */
	public executeUIAction<T extends IAbility>(
		tag: string,
		context: IContext,
		viewParams: IParam,
		data: IParam[],
		event: MouseEvent,
		ability: T
	): Promise<IUIActionResult> {
		const _this: any = this;
		if (hasFunction(_this, tag)) {
			return _this[tag](context, viewParams, data, event, ability);
		}
		console.error(`${tag} 行为不存在`);
		return Promise.reject({ ok: false, data: {} });
	}

	/**
	 * 执行界面逻辑
	 * @param tag 界面逻辑标识
	 * @param context 应用上下文
	 * @param viewParams 视图参数
	 * @param data 业务数据
	 * @param event 事件对象
	 * @param ability 当前环境能力
	 */
	public executeUILogic<T extends IAbility>(
		tag: string,
		context: IContext,
		viewParams: IParam,
		data: IParam[],
		event: MouseEvent,
		ability: T
	): Promise<IUIActionResult> {
		throw new Error('Method not implemented.');
	}

	/**
	 * 获取指定操作标识权限
	 *
	 * @param tag 操作标识tag
	 * @param data 业务数据
	 */
	public abstract getOPPrivsAuth(tag: string, data: IParam): number;

	/**
	 * 获取重定向视图
	 * @param context  应用上下文
	 * @param viewParams 视图参数
	 * @param data 当前业务数据
	 * @param redirectParam 重定向视图输入参数
	 */
	public getAppRDView(
		context: IContext,
		viewParams: IParam,
		data: IParam,
		redirectParam: IRedirectInput
	): Promise<IRedirectResult> {
		throw new Error('Method not implemented.');
	}

	/**
	 * 处理界面行为参数
	 *
	 */
	protected async handleUIActionParam(
		context: IContext,
		viewParams: IParam,
		data: IParam[],
		actionModel: IActionModel
	): Promise<{ context: IContext; viewParams: IParam; data: IParam[] }> {
		//  处理数据目标参数
		const targetParams = await this.handleTargetParams(
			context,
			data,
			actionModel
		);
		// 根据数据目标参数，合并导航参数
		return this.handleNavParams(
			context,
			viewParams,
			data,
			targetParams,
			actionModel
		);
	}

	/**
	 * 根据数据目标处理行为参数
	 *
	 * @param {string} action
	 * @param { IUIActionParams } params
	 * @memberof AppFrontAction
	 */
	protected async handleTargetParams(
		context: IContext,
		data: IParam[],
		actionModel: IActionModel
	): Promise<{
		targetContext: IParam;
		targetViewParams: IParam;
		targetData: IParam[];
	}> {
		const {
			actionTarget,
			entityCodeName,
			keyFieldCodeName,
			majorFieldCodeName,
		} = actionModel;
		//  数据目标值
		const targetContext: IParam = {};
		const targetViewParams: IParam = {};
		const targetData: IParam[] = [];
		if (actionTarget == 'SINGLEKEY' || actionTarget == 'MULTIKEY') {
			//  多数据主键和单数据主键，合并实体的主键参数和主信息参数 到上下文 后续统一合并进数据目标值
			if (!entityCodeName || !keyFieldCodeName || !majorFieldCodeName) {
				throw new Error('实体级界面行为参数不足');
			}
			const entityName = entityCodeName.toLowerCase();
			const keyField = keyFieldCodeName.toLowerCase();
			const majorField = majorFieldCodeName.toLowerCase();
			if (data && data.length > 0 && data[0][keyField]) {
				Object.assign(targetContext, {
					[entityName]: `%${keyField}%`,
				});
			} else {
				Object.assign(targetContext, {
					[entityName]: `%${entityName}%`,
				});
			}
			Object.assign(targetViewParams, {
				[keyField]: `%${keyField}%`,
			});
			Object.assign(targetViewParams, {
				[majorField]: `%${majorField}%`,
			});
		} else if (actionTarget == 'SINGLEDATA') {
			if (data && data.length > 0) {
				targetData.push(data[0]);
			}
		}
		return { targetContext, targetViewParams, targetData };
	}

	/**
	 * 处理行为参数 导航参数
	 *
	 * @
	 * @param {IParam} uiAction
	 * @param IUIActionParams params
	 * @memberof AppFrontAction
	 */
	protected handleNavParams(
		context: IContext,
		viewParams: IParam,
		data: IParam[],
		{ targetContext, targetViewParams, targetData }: IParam,
		actionModel: IActionModel
	): { context: IParam; viewParams: IParam; data: IParam[] } {
		const { navContexts, navParams, actionTarget } = actionModel;
		// 合并导航参数和导航上下文至数据目标处理后的参数
		const _targetContext = deepCopy(targetContext);
		const _targetViewParams = deepCopy(targetViewParams);
		if (navContexts) {
			Object.assign(_targetContext, navContexts);
		}
		if (navParams) {
			Object.assign(_targetViewParams, navParams);
		}
		//  根据上下文和导航参数，解析参数
		const _context = formatActionData(
			actionTarget,
			data,
			context,
			viewParams,
			_targetContext
		);
		const _viewParams = formatActionData(
			actionTarget,
			data,
			context,
			viewParams,
			_targetViewParams
		);
		//  单项数据并且目标数据中存在值时合并
		if (
			Object.is(actionTarget, 'SINGLEDATA') &&
			targetData &&
			targetData.length > 0
		) {
			Object.assign(targetData[0], _viewParams);
		} else {
			targetData = [_viewParams];
		}
		//
		Object.assign(context, _context);
		Object.assign(
			viewParams,
			targetData && targetData.length > 0 ? targetData[0] : {}
		);
		// 多项数据主键转换数据
		// if (Object.is(actionTarget, 'MULTIKEY')) {
		//   const tempDataArray: Array<any> = [];
		//   if (data.length > 1 && Object.keys(data).length > 0) {
		//     for (let i = 0; i < data.length; i++) {
		//       const tempObject: any = {};
		//       Object.keys(targetData).forEach((key: string) => {
		//         Object.assign(tempObject, { [key]: targetData[key].split(',')[i] });
		//       });
		//       tempDataArray.push(tempObject);
		//     }
		//   } else {
		//     tempDataArray.push(data);
		//   }
		//   targetData = tempDataArray;
		// }
		//
		return { context, viewParams, data };
	}

	/**
	 * 行为附加操作  刷新引用视图 & 关闭编辑或弹出视图 & 后续界面行为
	 *
	 * @param {IContext} context
	 * @param {IParam} viewParams
	 * @param {IParam[]} data
	 * @param {MouseEvent} event
	 * @param {IAbility} ability
	 * @memberof UIServiceBase
	 */
	protected afterAction(
		context: IContext,
		viewParams: IParam,
		data: IParam[],
		event: MouseEvent,
		ability: IAbility,
		actionModel: IActionModel
	): Promise<IUIActionResult> {
		const {
			refreshMode,
			reloadData,
			closeEditView,
			nextAction,
			uILogicAttachMode,
			deUILogicTag,
			entityCodeName,
		} = actionModel;
		// 刷新视图
		if (reloadData && hasFunction(ability, 'refresh')) {
			(ability as IMDCtrlAbility).refresh();
		}
		//  当刷新模式为刷新引用视图，且当前能力部件是表单时，全局刷新
		if (
			reloadData &&
			refreshMode === 1 &&
			ability.getModel().controlType === 'FORM'
		) {
			// todo
			// App.getNotificationHelper().info(entityCodeName, 'refresh');
		}
		// 关闭视图
		if (closeEditView) {
			(ability as IViewAbility).closeView();
		}
		// 后续界面行为
		if (!nextAction) {
			//  后续界面逻辑
			if (uILogicAttachMode === 'AFTER' && deUILogicTag) {
				return this.executeUILogic(
					deUILogicTag,
					context,
					viewParams,
					data,
					event,
					ability
				);
			}
			return Promise.resolve({ ok: true, data: data });
		}
		if (nextAction.predefinedType) {
			return App.getGlobalActionHelper().executeUIAction(
				nextAction.name,
				context,
				viewParams,
				data,
				event,
				ability
			);
		}
		if (nextAction.actionDeCodeName) {
			return new Promise((resolve: Function) => {
				App.getUIService(nextAction.actionDeCodeName as string).then(
					(service: IUIService) => {
						resolve(
							service.executeUIAction(
								nextAction.name,
								context,
								viewParams,
								data,
								event,
								ability
							)
						);
					}
				);
			});
		}
		return Promise.resolve({ ok: true, data: data });
	}

	/**
	 * 获取工作流视图
	 *
	 * @return {*}
	 * @memberof UIServiceBase
	 */
	 public getWFView(entityCodeName: string): any {
		const views: IParam = App.getAppViewConfig();
		const entityViewMap: Map<string, any> = new Map;
		for (const key in views) {
			const view: IViewDetail = views[key];
			(view.appEntityCodeName == entityCodeName) && entityViewMap.set(`${view.funcViewMode}:${view.funcViewParam}`, view);
		}
		let result = entityViewMap.get("WFEDITVIEW:");
		if (!result) {
			const allViews: any = entityViewMap.values();
			for (let value of allViews) {
				if (value.viewType === 'DEWFDYNAEDITVIEW') {
					return value;
				}
			}
		} else {
			return result;
		}
	}
}
